from django import forms
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from django_redis import get_redis_connection
from utils.common import myMd5
from web.models import UserInfo

from utils.bootstrap import BootstrapModelForm,BootstrapForm
class RegisterModelForm(BootstrapModelForm):
    # 当form需要用到视图中的数据时，可以通过重写init方法 传入参数的方式 调用视图中的数据
    def __init__(self,request,*args,**kwargs):
        super().__init__(*args,**kwargs)
        self.request = request
    # 这里如果想排除某个字段不想使用bootstrap样式的，可以使用 bootstrap_class_exclude = [字段]
    # bootstrap_class_exclude = ['user_name']
    user_name = forms.CharField(label='用户名',validators=[RegexValidator(r'^[a-zA-Z0-9-_]{3,16}$','3到16位（字母，数字，下划线，减号）')])
    email = forms.CharField(label='邮箱',validators=[RegexValidator(r'^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$','邮箱格式错误')])
    mobile_phone = forms.CharField(label="手机号",validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$','手机号格式错误'),])
    password = forms.CharField(label="密码",widget=forms.PasswordInput())
    confirm_password = forms.CharField(label="确认密码",widget=forms.PasswordInput())
    code = forms.CharField(label="验证码",max_length=32,widget=forms.TextInput())
    class Meta:
        model = UserInfo
        # 显示所有字段
        # fields = "__all__"
        fields = ['user_name','email','password','confirm_password','mobile_phone','code']
        # 排除不需要显示的字段
        # exclude = ['user_name']
    #校验用户名的钩子函数
    def clean_user_name(self):
        user_name = self.cleaned_data['user_name'] #定义变量接收表单传递过来的用户名
        exists = UserInfo.objects.filter(user_name=user_name).exists()
        if exists:
            raise ValidationError('用户名已被占用')
        return user_name

    # 校验用户名的钩子函数
    def clean_email(self):
        email = self.cleaned_data['email']  # 定义变量接收表单传递过来的用户名
        exists = UserInfo.objects.filter(email=email).exists()
        if exists:
            # self.add_error('email','邮箱已被占用')
            raise ValidationError('邮箱已被占用')
        return email
    def clean_password(self):
        password = self.cleaned_data.get('password')
        return myMd5(password)
    # 校验密码的钩子函数
    def clean_confirm_password(self):
        password = self.cleaned_data.get('password')
        confirm_password = myMd5(self.cleaned_data.get('confirm_password'))
        # 由于confirm_password 不在models里面所以需要通过request获取，因此需要重写init方法
        if password != confirm_password:
            raise ValidationError('密码不一致')
        return confirm_password
    def clean_mobile_phone(self):
        # 根据fields的先后顺序 cleaned_data只能获取当前钩子函数之前的数据值
        # print(self.cleaned_data['password'],self.cleaned_data['confirm_password'],self.cleaned_data['code'])
        mobile_phone = self.cleaned_data.get('mobile_phone')
        exists = UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exists:
            raise ValidationError("手机号已注册")
        return mobile_phone
    def clean_code(self):
        sms_code = self.cleaned_data.get('code')
        conn = get_redis_connection('sms_code')
        # mobile_phone = self.cleaned_data['mobile_phone'] #如果用这个可能会报错，因为前面没有验证通过的话，cleaned_data就没有mobile_phone这个 key
        mobile_phone = self.request.POST.get('mobile_phone') #提交注册时用提交过来的手机号，去redis中取验证码，防止提交注册前手机号与获取验证码时的号码 对不上
        redis_sms_code = conn.get(mobile_phone) # 如果根据手机号在，redis中取不到数据,返回None 可能是过期了 也可能是手机号 对不上接收验证码的号码
        if not redis_sms_code:
            raise ValidationError('手机验证码失效，请重新获取')
        if sms_code.strip() != redis_sms_code.decode('utf-8'):
            raise  ValidationError('手机验证码输入错误')
        return sms_code

class SendSmsForm(forms.Form):
    mobile_phone = forms.CharField(label="手机号",validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$','手机号格式错误'),])

    def __init__(self,request,*args,**kwargs):
        super().__init__(*args,**kwargs)
        self.request = request
    """
    先执行上面的正则表达式校验，再执行钩子函数
    """
    def clean_mobile_phone(self):
        """手机号的钩子函数，用于手机号的校验"""
        mobile_phone = self.cleaned_data['mobile_phone']# self.cleaned_data 获取表单传递过来的数据
        tpl = self.request.GET.get('tpl')
        # 通过数据库查询手机号是否已经存在
        exists = UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        # exists = UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if tpl == 'login':
            if not exists:
                raise ValidationError('该账号不存在')
        else:
            if exists:
                raise ValidationError('手机号已存在')
        return mobile_phone

class LoginForm(BootstrapForm):
    user_name = forms.CharField(label='用户名/邮箱/手机号')
    password = forms.CharField(label='密码',widget=forms.PasswordInput())
    code = forms.CharField(label='验证码')

    def __init__(self,request,*args,**kwargs):
        super().__init__(*args,**kwargs)
        self.request = request
    # 这里得返回md5加密之后的密码，因为数据库中存储的密文
    def clean_password(self):
        password = self.cleaned_data.get('password')
        return myMd5(password)
    def clean_code(self):
        # 获取到表单传递的验证码
        code = self.cleaned_data.get('code')
        # 获取存储在session中的验证码
        s_code = self.request.session.get('code')
        print(s_code,code,'看这里***********')
        if not s_code:
            raise ValidationError('验证码已过期!')
        if s_code.strip().upper() != code.strip().upper():
            raise ValidationError('验证码错误!')
        return s_code

class LoginSmsForm(BootstrapForm):
    mobile_phone = forms.CharField(label="手机号", validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])
    code = forms.CharField(label='验证码')
    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data.get('mobile_phone')
        user_obj = UserInfo.objects.filter(mobile_phone=mobile_phone).first()
        if not user_obj:
            self.add_error('mobile_phone','该账号不存在')
        return user_obj
    def clean_code(self):
        # 注意这里获取到的是 上面返回的user_obj
        user_obj = self.cleaned_data.get('mobile_phone')
        sms_code = self.cleaned_data.get('code')
        conn = get_redis_connection('sms_code')
        # mobile_phone = self.cleaned_data['mobile_phone'] #如果用这个可能会报错，因为前面没有验证通过的话，cleaned_data就没有mobile_phone这个 key
        redis_sms_code = conn.get(user_obj.mobile_phone)  # 如果根据手机号在，redis中取不到数据,返回None 可能是过期了 也可能是手机号 对不上接收验证码的号码
        if not redis_sms_code:
            raise ValidationError('手机验证码失效，请重新获取')
        if sms_code.strip() != redis_sms_code.decode('utf-8'):
            raise ValidationError('手机验证码输入错误')
        return sms_code

